﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;

namespace ZOIL.Library.Behaviors
{
    public class ObjectManipulationBehavior : RuntimeBehavior<FrameworkElement, PluginObjectManipulationBehavior>
    {
        #region Routed Events

        #region DragDrop Events
        
        public delegate void DragDropEventHandler(object sender, DragDropEventArgs args);

        #region DragStarted

        public static readonly RoutedEvent DragStartedEvent = EventManager.RegisterRoutedEvent("DragStarted", RoutingStrategy.Bubble, typeof(DragDropEventHandler), typeof(ObjectManipulationBehavior));

        public event DragDropEventHandler DragStarted
        {
            add { AddRoutedEventHandler(DragStartedEvent, value); }
            remove { RemoveRoutedEventHandler(DragStartedEvent, value); }
        }

        #endregion

        #region DragFinished

        public static readonly RoutedEvent DragFinishedEvent = EventManager.RegisterRoutedEvent("DragFinished", RoutingStrategy.Bubble, typeof(DragDropEventHandler), typeof(ObjectManipulationBehavior));

        public event DragDropEventHandler DragFinished
        {
            add { AddRoutedEventHandler(DragFinishedEvent, value); }
            remove { RemoveRoutedEventHandler(DragFinishedEvent, value); }
        }

        #endregion

        #region DragChanged

        public static readonly RoutedEvent DragChangedEvent = EventManager.RegisterRoutedEvent("DragChanged", RoutingStrategy.Bubble, typeof(DragDropEventHandler), typeof(ObjectManipulationBehavior));

        public event DragDropEventHandler DragChanged
        {
            add { AddRoutedEventHandler(DragChangedEvent, value); }
            remove { RemoveRoutedEventHandler(DragChangedEvent, value); }
        }

        #endregion

        #endregion

        #endregion

        #region dependency properties

        #region IsResizable

        /// <summary>
        /// IsResizable Dependency Property
        /// </summary>
        public static DependencyProperty IsResizableProperty = DependencyProperty.RegisterAttached("IsResizable", typeof(bool), typeof(ObjectManipulationBehavior), new FrameworkPropertyMetadata(false, OnIsResizableChanged));

        /// <summary>
        /// Gets or sets the IsResizable property. This dependency property 
        /// indicates ....
        /// </summary>
        public bool IsResizable
        {
            get { return (bool)GetValue(IsResizableProperty); }
            set { SetValue(IsResizableProperty, value); }
        }

        /// <summary>
        /// Handles changes to the IsResizable property.
        /// </summary>
        private static void OnIsResizableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = (ObjectManipulationBehavior)d;
            var oldIsResizable = (bool)e.OldValue;
            var newIsResizable = target.IsResizable;
            target.OnIsResizableChanged(oldIsResizable, newIsResizable);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the IsResizable property.
        /// </summary>
        protected virtual void OnIsResizableChanged(bool oldIsResizable, bool newIsResizable)
        {
        }

        #endregion

        #region IsRotatable

        /// <summary>
        /// IsRotatable Dependency Property
        /// </summary>
        public static DependencyProperty IsRotatableProperty = DependencyProperty.RegisterAttached("IsRotatable", typeof(bool), typeof(ObjectManipulationBehavior), new FrameworkPropertyMetadata(false, OnIsRotatableChanged));

        /// <summary>
        /// Gets or sets the IsRotatable property. This dependency property 
        /// indicates ....
        /// </summary>
        public bool IsRotatable
        {
            get { return (bool)GetValue(IsRotatableProperty); }
            set { SetValue(IsRotatableProperty, value); }
        }

        /// <summary>
        /// Handles changes to the IsRotatable property.
        /// </summary>
        private static void OnIsRotatableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = (ObjectManipulationBehavior)d;
            var oldIsRotatable = (bool)e.OldValue;
            var newIsRotatable = target.IsRotatable;
            target.OnIsRotatableChanged(oldIsRotatable, newIsRotatable);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the IsRotatable property.
        /// </summary>
        protected virtual void OnIsRotatableChanged(bool oldIsRotatable, bool newIsRotatable)
        {
        }

        #endregion

        #region IsDraggable

        /// <summary>
        /// IsDraggable Dependency Property
        /// </summary>
        public static DependencyProperty IsDraggableProperty = DependencyProperty.RegisterAttached("IsDraggable", typeof(bool), typeof(ObjectManipulationBehavior), new FrameworkPropertyMetadata(false, OnIsDraggableChanged));

        /// <summary>
        /// Gets or sets the IsDraggable property. This dependency property 
        /// indicates ....
        /// </summary>
        public bool IsDraggable
        {
            get { return (bool)GetValue(IsDraggableProperty); }
            set { SetValue(IsDraggableProperty, value); }
        }

        /// <summary>
        /// Handles changes to the IsDraggable property.
        /// </summary>
        private static void OnIsDraggableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = (ObjectManipulationBehavior)d;
            var oldIsDraggable = (bool)e.OldValue;
            var newIsDraggable = target.IsDraggable;
            target.OnIsDraggableChanged(oldIsDraggable, newIsDraggable);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the IsDraggable property.
        /// </summary>
        protected virtual void OnIsDraggableChanged(bool oldIsDraggable, bool newIsDraggable)
        {
        }

        #endregion

        #region IsDragging

        /// <summary>
        /// IsDragging Dependency Property
        /// </summary>
        public static DependencyProperty IsDraggingProperty = DependencyProperty.RegisterAttached("IsDragging", typeof(bool), typeof(ObjectManipulationBehavior), new FrameworkPropertyMetadata(false, OnIsDraggingChanged));

        /// <summary>
        /// Gets or sets the IsDragging property. This dependency property 
        /// indicates ....
        /// </summary>
        public bool IsDragging
        {
            get { return (bool)GetValue(IsDraggingProperty); }
            set { SetValue(IsDraggingProperty, value); }
        }

        /// <summary>
        /// Handles changes to the IsDragging property.
        /// </summary>
        private static void OnIsDraggingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = (ObjectManipulationBehavior)d;
            var oldIsDragging = (bool)e.OldValue;
            var newIsDragging = target.IsDragging;
            target.OnIsDraggableChanged(oldIsDragging, newIsDragging);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the IsDragging property.
        /// </summary>
        protected virtual void OnIsDraggingChanged(bool oldIsDragging, bool newIsDragging)
        {
        }

        #endregion

        #region IsInertiaEnabled

        public bool IsInertiaEnabled
        {
            get { return (bool)GetValue(IsInertiaEnabledProperty); }
            set { SetValue(IsInertiaEnabledProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsInertiaEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsInertiaEnabledProperty =
            DependencyProperty.Register("IsInertiaEnabled", typeof(bool), typeof(ObjectManipulationBehavior), new PropertyMetadata(true, OnIsInertiaEnabledChanged));

        /// <summary>
        /// Handles changes to the IsDragging property.
        /// </summary>
        private static void OnIsInertiaEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = (ObjectManipulationBehavior)d;
            var oldIsDragging = (bool)e.OldValue;
            var newIsDragging = target.IsDragging;
            target.OnIsInertiaEnabledChanged(oldIsDragging, newIsDragging);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the IsDragging property.
        /// </summary>
        protected virtual void OnIsInertiaEnabledChanged(bool oldIsDragging, bool newIsDragging)
        {
        }

        #endregion

        #endregion

        #region event helper

        #region DragDrop Events

        internal void RaiseDragStartedEvent(Point point)
        {
            var args = new DragDropEventArgs(DragStartedEvent, point) { Source = this };
            AssociatedObject.RaiseEvent(args);
        }

        internal void RaiseDragFinishedEvent(Point point)
        {
            var args = new DragDropEventArgs(DragFinishedEvent, point) { Source = this };
            AssociatedObject.RaiseEvent(args);
        }

        internal void RaiseDragFinishedEvent(FrameworkElement element, Point point)
        {
            var args = new DragDropEventArgs(DragFinishedEvent, point) { Source = this };
            element.RaiseEvent(args);
        }

        internal void RaiseDragChangedEvent(Point point)
        {
            var args = new DragDropEventArgs(DragChangedEvent, point) { Source = this };
            AssociatedObject.RaiseEvent(args);
        } 

        #endregion

        #endregion
    }
}
